package com.szcinda.call.service;

import com.szcinda.call.OrderDetailQueryDto;
import com.szcinda.call.PageResult;
import com.szcinda.call.SnowFlakeFactory2;
import com.szcinda.call.repository.*;
import org.springframework.beans.BeanUtils;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.persistence.criteria.Predicate;
import java.util.ArrayList;
import java.util.List;


@Service
@Transactional
public class OrderDetailServiceImpl implements OrderDetailService {
    private final OrderDetailRepository orderDetailRepository;
    private final GhzhInfoRepository ghzhInfoRepository;
    private final GhzhDetailRepository ghzhDetailRepository;
    private final GhzhGoodsRepository ghzhGoodsRepository;
    private final GhzhShipRepository ghzhShipRepository;
    private final SnowFlakeFactory2 snowFlakeFactory;

    public OrderDetailServiceImpl(OrderDetailRepository orderDetailRepository, GhzhInfoRepository ghzhInfoRepository,
                                  GhzhDetailRepository ghzhDetailRepository, GhzhGoodsRepository ghzhGoodsRepository,
                                  GhzhShipRepository ghzhShipRepository) {
        this.orderDetailRepository = orderDetailRepository;
        this.ghzhInfoRepository = ghzhInfoRepository;
        this.ghzhDetailRepository = ghzhDetailRepository;
        this.ghzhGoodsRepository = ghzhGoodsRepository;
        this.ghzhShipRepository = ghzhShipRepository;
        this.snowFlakeFactory = SnowFlakeFactory2.getInstance();
    }

    @Override
    public void insertByBooking(BookingOrderDetailInsertDto insertDto) {
        OrderDetail record = null;
        if (!StringUtils.isEmpty(insertDto.getBookingNumber()) && !StringUtils.isEmpty(insertDto.getPickingNumber())) {
            record = orderDetailRepository.findByBookingNumberAndPickingNumberAndUserName(insertDto.getBookingNumber(),insertDto.getPickingNumber(), insertDto.getUserName());
        }else if(!StringUtils.isEmpty(insertDto.getBookingNumber())) {
            record = orderDetailRepository.findByBookingNumberAndUserName(insertDto.getBookingNumber(), insertDto.getUserName());
        }else if(!StringUtils.isEmpty(insertDto.getPickingNumber())) {
            record = orderDetailRepository.findByPickingNumberAndUserName(insertDto.getPickingNumber(), insertDto.getUserName());
        }
        if (insertDto.getInsertType() == 1) {
            if (record == null) {
                record = new OrderDetail();
                record.setId(snowFlakeFactory.nextId("OD"));
                record.setUserName(insertDto.getUserName());
            }
            BeanUtils.copyProperties(insertDto, record, "id", "userName");
            orderDetailRepository.save(record);
        }else if (insertDto.getInsertType() == 2) {
            if (record == null) {
                record = new OrderDetail();
                record.setId(snowFlakeFactory.nextId("OD"));
                BeanUtils.copyProperties(insertDto, record, "id");
                orderDetailRepository.save(record);
            }
        }
    }

    @Override
    public void insertByPicking(PickingOrderDetailInsertDto insertDto) {
        GhzhInfo record = ghzhInfoRepository.findByPickingNumberAndCntrNo(insertDto.getPickingNumber(), insertDto.getCntrNo());
        if (record == null) {
            record = new GhzhInfo();
            record.setId(snowFlakeFactory.nextId("OD"));
        }
        String id = record.getId();
        GhzhDetail detail = ghzhDetailRepository.findByGhzhId(id);
        if (detail == null) {
            detail = new GhzhDetail();
            detail.setId(snowFlakeFactory.nextId("OD"));
            detail.setGhzhId(id);
        }
        GhzhGoods goods = ghzhGoodsRepository.findByGhzhId(id);
        if (goods == null) {
            goods = new GhzhGoods();
            goods.setId(snowFlakeFactory.nextId("OD"));
            goods.setGhzhId(id);
        }
//        ghzhGoodsRepository.deleteByGhzhId(id);
//        insertDto.getGoods().forEach(goods -> {
//            GhzhGoods ghzhGoods = new GhzhGoods();
//            BeanUtils.copyProperties(goods, ghzhGoods, "id");
//            ghzhGoods.setId(snowFlakeFactory.nextId("OD"));
//            ghzhGoods.setGhzhId(id);
//            ghzhGoodsRepository.save(ghzhGoods);
//        });
        GhzhShip ship = ghzhShipRepository.findByGhzhId(id);
        if (ship == null) {
            ship = new GhzhShip();
            ship.setId(snowFlakeFactory.nextId("OD"));
            ship.setGhzhId(id);
        }
        BeanUtils.copyProperties(insertDto.getGhzhDetail(), detail, "id", "ghzhId");
        ghzhDetailRepository.save(detail);
        BeanUtils.copyProperties(insertDto.getGoods(), goods, "id", "ghzhId");
        ghzhGoodsRepository.save(goods);
        BeanUtils.copyProperties(insertDto.getShip(), ship, "id", "ghzhId");
        ghzhShipRepository.save(ship);
        BeanUtils.copyProperties(insertDto, record, "id");
        ghzhInfoRepository.save(record);
    }

    @Override
    public PageResult<OrderDetailDto> query(OrderDetailQueryDto params) {
        Specification<OrderDetail> specification = ((root, criteriaQuery, criteriaBuilder) -> {
            List<Predicate> predicates = new ArrayList<>();
            Predicate userName = criteriaBuilder.equal(root.get("userName").as(String.class), params.getUserName().trim());
            predicates.add(userName);
            if (!StringUtils.isEmpty(params.getBookingNumber())) {
                Predicate bookingNumber = criteriaBuilder.like(root.get("bookingNumber").as(String.class), params.getBookingNumber().trim() + "%");
                predicates.add(bookingNumber);
            }
            if (!StringUtils.isEmpty(params.getPickingNumber())) {
                Predicate pickingNumber = criteriaBuilder.like(root.get("pickingNumber").as(String.class), params.getPickingNumber().trim() + "%");
                predicates.add(pickingNumber);
            }
            if (params.getCreateTimeStart() != null) {
                Predicate start = criteriaBuilder.greaterThanOrEqualTo(root.get("createTime"), params.getCreateTimeStart().atStartOfDay());
                predicates.add(start);
            }
            if (params.getCreateTimeEnd() != null) {
                Predicate createTimeEnd = criteriaBuilder.lessThanOrEqualTo(root.get("createTime"), params.getCreateTimeEnd().plusDays(1).atStartOfDay());
                predicates.add(createTimeEnd);
            }
            return criteriaBuilder.and(predicates.toArray(new Predicate[0]));
        });
        Sort order = Sort.by(Sort.Direction.DESC, "createTime");
        Pageable pageable = PageRequest.of(params.getPage() - 1, params.getPageSize(), order);
        Page<OrderDetail> details = orderDetailRepository.findAll(specification, pageable);

        List<OrderDetail> detailList = details.getContent();
        List<OrderDetailDto> dtos = new ArrayList<>(detailList.size());
        detailList.forEach(detail -> {
            OrderDetailDto dto = new OrderDetailDto();
            BeanUtils.copyProperties(detail, dto);
            List<GhzhInfo> ghzhInfos = ghzhInfoRepository.findAllByPickingNumber(detail.getPickingNumber());
            List<OrderDetailDto.GhzhDto> ghzhDtos = new ArrayList<>(ghzhInfos.size());
            ghzhInfos.forEach(info -> {
                OrderDetailDto.GhzhDto ghzhDto = new OrderDetailDto.GhzhDto();
                GhzhDetail ghzhDetail = ghzhDetailRepository.findByGhzhId(info.getId());
                GhzhGoods ghzhGoods = ghzhGoodsRepository.findByGhzhId(info.getId());
                GhzhShip ghzhShip = ghzhShipRepository.findByGhzhId(info.getId());
                ghzhDto.setGhzhInfo(info);
                ghzhDto.setGhzhDetail(ghzhDetail);
                ghzhDto.setGhzhGoods(ghzhGoods);
                ghzhDto.setGhzhShip(ghzhShip);
                ghzhDtos.add(ghzhDto);
            });
            dto.setGhzhDtos(ghzhDtos);
            dtos.add(dto);
        });

        return PageResult.of(dtos, params.getPage(), params.getPageSize(), details.getTotalElements());
    }

    @Override
    public List<OrderDetailDto> queryExportData(OrderDetailQueryDto params) {
        Specification<OrderDetail> specification = ((root, criteriaQuery, criteriaBuilder) -> {
            List<Predicate> predicates = new ArrayList<>();
            Predicate userName = criteriaBuilder.equal(root.get("userName").as(String.class), params.getUserName().trim());
            predicates.add(userName);
            if (!StringUtils.isEmpty(params.getBookingNumber())) {
                Predicate bookingNumber = criteriaBuilder.like(root.get("bookingNumber").as(String.class), params.getBookingNumber().trim() + "%");
                predicates.add(bookingNumber);
            }
            if (!StringUtils.isEmpty(params.getPickingNumber())) {
                Predicate pickingNumber = criteriaBuilder.like(root.get("pickingNumber").as(String.class), params.getPickingNumber().trim() + "%");
                predicates.add(pickingNumber);
            }
            if (params.getCreateTimeStart() != null) {
                Predicate start = criteriaBuilder.greaterThanOrEqualTo(root.get("createTime"), params.getCreateTimeStart().atStartOfDay());
                predicates.add(start);
            }
            if (params.getCreateTimeEnd() != null) {
                Predicate createTimeEnd = criteriaBuilder.lessThanOrEqualTo(root.get("createTime"), params.getCreateTimeEnd().plusDays(1).atStartOfDay());
                predicates.add(createTimeEnd);
            }
            return criteriaBuilder.and(predicates.toArray(new Predicate[0]));
        });
        Sort order = Sort.by(Sort.Direction.DESC, "createTime");
        List<OrderDetail> details = orderDetailRepository.findAll(specification, order);

        List<OrderDetailDto> dtos = new ArrayList<>(details.size());
        details.forEach(detail -> {
            OrderDetailDto dto = new OrderDetailDto();
            BeanUtils.copyProperties(detail, dto);
            List<GhzhInfo> ghzhInfos = ghzhInfoRepository.findAllByPickingNumber(detail.getPickingNumber());
            List<OrderDetailDto.GhzhDto> ghzhDtos = new ArrayList<>(ghzhInfos.size());
            ghzhInfos.forEach(info -> {
                OrderDetailDto.GhzhDto ghzhDto = new OrderDetailDto.GhzhDto();
                GhzhDetail ghzhDetail = ghzhDetailRepository.findByGhzhId(info.getId());
                GhzhGoods ghzhGoods = ghzhGoodsRepository.findByGhzhId(info.getId());
                GhzhShip ghzhShip = ghzhShipRepository.findByGhzhId(info.getId());
                ghzhDto.setGhzhInfo(info);
                ghzhDto.setGhzhDetail(ghzhDetail);
                ghzhDto.setGhzhGoods(ghzhGoods);
                ghzhDto.setGhzhShip(ghzhShip);
                ghzhDtos.add(ghzhDto);
            });
            dto.setGhzhDtos(ghzhDtos);
            dtos.add(dto);
        });
        return dtos;
    }
}
